package cn.safekeeper.plugin.configuration;

import cn.safekeeper.common.configuration.SafeKeeperCodeMsgConfiguration;
import cn.safekeeper.common.configuration.SafeKeeperConfiguration;
import cn.safekeeper.common.constant.SafeKeeperConstant;
import cn.safekeeper.common.model.SafeKeeperAuthorizationCallBack;
import cn.safekeeper.common.model.SafeKeeperContext;
import cn.safekeeper.common.utils.SafeKeeperUtils;
import cn.safekeeper.core.SafeKeeper;
import cn.safekeeper.core.listener.SafeKeeperTokenListener;
import cn.safekeeper.core.manager.SafeKeeperManager;
import cn.safekeeper.core.manager.SafeKeeperTokenRealm;
import cn.safekeeper.plugin.aop.SafeKeeperCheckAspect;
import cn.safekeeper.plugin.context.SpringSafeKeeperContext;
import cn.safekeeper.plugin.filter.SafeKeeperFilter;
import cn.safekeeper.plugin.redis.config.SafeRedisProperties;
import cn.safekeeper.plugin.redisson.dao.SafeKeeperTokenRealmRedisson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.servlet.http.HttpServletRequest;

/**
 * SafeKeeper配置启动类
 *
 * @author skylark
 */
@Configuration
@ComponentScan("cn.safekeeper.plugin.web")
public class SafeKeeperAutoConfiguration {

	/**
	 * 切面初始化
	 */
	@Bean
	public SafeKeeperCheckAspect getSafeKeeperCheckAspect() {
		return new SafeKeeperCheckAspect();
	}

	/**
	 * context初始化
	 */
	@Bean
	public SafeKeeperContext getSafeKeeperContext() {
		return new SpringSafeKeeperContext();
	}

	@Bean
	@ConfigurationProperties(prefix = "spring.safekeeper")
	public SafeKeeperConfiguration getSafeKeeperConfiguration() {
		return new SafeKeeperConfiguration();
	}


	/**
	 * SafeKeeperManager 注入 SafeKeeperConfiguration
	 * 配置文件 Bean
	 */
	@Autowired
	public void setConfig(SafeKeeperConfiguration config) {
		SafeKeeperManager.setConfig(config);
	}

	@Bean
	public SafeRedisProperties getSafeRedisProperties() {
		return new SafeRedisProperties();
	}

	@Bean
	public SafeKeeperTokenRealm safeKeeperTokenRealmRedisson(SafeRedisProperties cfg) {
		return new SafeKeeperTokenRealmRedisson(cfg);
	}

	/**
	 * SafeKeeperManager SafeKeeperTokenDaoStorage
	 * 持久化Dao Bean
	 */
	@Autowired
	public void setSafeKeeperTokenRealm(SafeKeeperTokenRealm safeKeeperTokenRealm) {
		SafeKeeperManager.setSafeKeeperTokenRealm(safeKeeperTokenRealm);
	}

	/**
	 * SafeKeeperManager SafeKeeperAuthorizationCallBack
	 * 权限认证 Bean
	 */
	@Autowired(required = false)
	public void setStpInterface(SafeKeeperAuthorizationCallBack authorizationCallBack) {
		SafeKeeperManager.setSafeKeeperAuthorizationCallBack(authorizationCallBack);
	}

	/**
	 * 容器操作 Bean
	 */
	@Autowired
	public void setSafeKeeperContext(SafeKeeperContext safeKeeperContext) {
		SafeKeeperManager.setSafeKeeperContext(safeKeeperContext);
	}

	/**
	 * SafeKeeperManager SafeKeeperTokenListener
	 * 侦听器 Bean
	 */
	@Autowired(required = false)
	public void setSafeKeeperTokenListener(SafeKeeperTokenListener tokenListener) {
		SafeKeeperManager.setSafeKeeperTokenListener(tokenListener);
	}

	/**
	 * SafeKeeperManager SafeKeeperCodeMsgConfiguration
	 * 状态消息配置 Bean
	 */
	@Autowired(required = false)
	public void setSafeKeeperCodeMsgConfiguration(SafeKeeperCodeMsgConfiguration safeKeeperCodeMsgConfiguration) {
		SafeKeeperManager.setSafeKeeperCodeMsgConfiguration(safeKeeperCodeMsgConfiguration);
	}

	@Bean
	public SafeKeeperFilter getSaServletFilter(SafeKeeperConfiguration config) {
		return new SafeKeeperFilter()
				// 指定 拦截路由 与 放行路由
				.addInclude("/**")
				.addExclude("/login")
				.addExclude("/error")
				.setExcludeList(config.getExcludeList())
				.setIncludeList(config.getIncludeList())
				// 认证函数: 每次请求执行
				.setAuth(r -> {
					HttpServletRequest request = (HttpServletRequest) r;
					//获取登录的方式
					String loginType = request.getHeader(SafeKeeperConstant.LOGIN_TYPE);
					//如果header中的数据为空，尝试去参数中获取。
					if (SafeKeeperUtils.isEmpty(loginType)) {
						//对参数进行获取loginType
						loginType = request.getParameter(SafeKeeperConstant.LOGIN_TYPE);
					}
					//如果用户是没有带loginType的参数，那么就默认是safekeeper维度进行登录
					if (SafeKeeperUtils.isEmpty(loginType)) {
						loginType = SafeKeeperManager.getConfig().getDefaultLoginType();
					}
					SafeKeeper.safeLogic(loginType).checkLogin();
				})
				// 异常处理函数：每次认证函数发生异常时执行此函数
				.setError(Throwable::getMessage)
				// 前置函数：在每次认证函数之前执行
				.setBeforeAuth(r -> {
					//安全响应头
					SafeKeeperManager.getSafeKeeperContext().getResponse()
							.setServer("safekeeper-server")
							.setHeader("X-XSS-Protection", "1; mode=block")
							.setHeader("X-Content-Type-Options", "nosniff");
				});
	}
}
